Skip to content

feat(iamcredentials): add generateAccessToken support#91

Open
snazy wants to merge 1 commit into
floci-io:mainfrom
snazy:cred-vending-1
Open

feat(iamcredentials): add generateAccessToken support#91
snazy wants to merge 1 commit into
floci-io:mainfrom
snazy:cred-vending-1

Conversation

@snazy

@snazy snazy commented Jul 15, 2026

Copy link
Copy Markdown

Adds the IAM Credentials REST emulator surface for local credential vending, including generateAccessToken validation, service enablement wiring, REST tests, and Java generated-client compatibility coverage.

  • New feature (feat:)

Implements the IAM Credentials v1 HTTP/JSON generateAccessToken path used by the Google Java IAM Credentials client. Verified with IamCredentialsServiceTest, IamCredentialsRestIntegrationTest, IamCredentialsDisabledRestIntegrationTest, IamServiceTest, and compatibility-tests/sdk-test-java IamCredentialsTest against a running emulator.

  • ./mvnw test passes locally
  • New or updated integration test added
  • Commit messages follow Conventional Commits

@snazy

snazy commented Jul 15, 2026

Copy link
Copy Markdown
Author

This PR contains the 1st commit of #90

@greptile-apps

greptile-apps Bot commented Jul 15, 2026

Copy link
Copy Markdown

Greptile Summary

This PR adds the IAM Credentials v1 REST emulator surface, implementing generateAccessToken to support local credential vending — including scope validation, lifetime parsing, service enablement wiring, and compatibility with the Google Java IAM Credentials client via HTTP/JSON transport.

  • IamCredentialsController / IamCredentialsService: New JAX-RS controller at /v1/projects/-/serviceAccounts/{serviceAccount}:generateAccessToken backed by a service that validates scopes (both devstorage.read_write and cloud-platform), parses and caps lifetime, and returns a floci-gcp-impersonated-<UUID> token with an expiry timestamp.
  • Config wiring: EmulatorConfig gains IamCredentialsServiceConfig, both YAML files are updated, and the service registers itself via ServiceRegistry.onStart to support the iamcredentials.enabled toggle.
  • Tests: Comprehensive unit tests (IamCredentialsServiceTest), REST integration tests (IamCredentialsRestIntegrationTest, IamCredentialsDisabledRestIntegrationTest), and a compatibility test against the Java SDK (IamCredentialsTest).

Confidence Score: 5/5

This PR is safe to merge. It adds a well-isolated new service with no mutations to existing routes and comprehensive test coverage across unit, integration, and SDK compatibility layers.

The implementation is stateless, follows all existing service patterns (constructor injection, GcpException, ServiceRegistry, config wiring), and does not touch any existing paths. The scope whitelist correctly covers both devstorage.read_write and cloud-platform. Lifetime parsing is defensive and thoroughly tested. Route precedence against the IAM catch-all wildcard is exercised by the integration tests. No correctness issues were found in the changed files.

No files require special attention.

Important Files Changed

Filename Overview
src/main/java/io/floci/gcp/services/iamcredentials/IamCredentialsService.java Core business logic: scope validation (supports devstorage.read_write + cloud-platform via anyMatch), lifetime parsing with cap at 3600s, testable via package-private Clock constructor. No state stored, no concurrency concerns.
src/main/java/io/floci/gcp/services/iamcredentials/IamCredentialsController.java Thin JAX-RS controller with constructor injection; correctly routes POST to /{serviceAccount}:generateAccessToken and delegates to the service.
src/test/java/io/floci/gcp/services/iamcredentials/IamCredentialsRestIntegrationTest.java Good coverage of happy paths and error cases; specificRouteDoesNotFallThroughToIamCatchAll overlaps with unsupportedScopeReturnsGcpStyleError in assertions (previously noted).
src/test/java/io/floci/gcp/services/iamcredentials/IamCredentialsServiceTest.java Comprehensive unit tests with fixed clock; covers normal path, default/capped lifetime, scope acceptance/rejection, and format validation.
compatibility-tests/sdk-test-java/src/test/java/io/floci/gcp/test/IamCredentialsTest.java SDK compatibility test using newHttpJsonBuilder(); delegates list is empty which is valid, and cloud-platform scope is correctly accepted by the updated service.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant Client as GCP SDK Client
    participant Controller as IamCredentialsController
    participant Service as IamCredentialsService
    participant Registry as ServiceRegistry

    Note over Service, Registry: Application startup
    Service->>Registry: register(iamcredentials, enabled, REST, IamCredentialsController)

    Note over Client, Service: Runtime request
    Client->>Controller: "POST /v1/projects/-/serviceAccounts/{email}:generateAccessToken"
    Controller->>Controller: Extract scope list and lifetime from body
    Controller->>Service: generateAccessToken(serviceAccount, scopes, lifetime)
    Service->>Service: validateServiceAccount(non-blank)
    Service->>Service: validateScopes(anyMatch SUPPORTED_SCOPES)
    Service->>Service: parseLifetimeSeconds(cap at MAX 3600s)
    Service-->>Controller: GeneratedAccessToken(prefix+UUID, expireTime)
    Controller-->>Client: "200 { accessToken, expireTime }"

    Note over Client, Service: Error cases
    Client->>Controller: POST (missing/unsupported scope or malformed lifetime)
    Controller->>Service: generateAccessToken(...)
    Service-->>Controller: throws GcpException(INVALID_ARGUMENT)
    Controller-->>Client: "400 { error: { status: INVALID_ARGUMENT } }"
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant Client as GCP SDK Client
    participant Controller as IamCredentialsController
    participant Service as IamCredentialsService
    participant Registry as ServiceRegistry

    Note over Service, Registry: Application startup
    Service->>Registry: register(iamcredentials, enabled, REST, IamCredentialsController)

    Note over Client, Service: Runtime request
    Client->>Controller: "POST /v1/projects/-/serviceAccounts/{email}:generateAccessToken"
    Controller->>Controller: Extract scope list and lifetime from body
    Controller->>Service: generateAccessToken(serviceAccount, scopes, lifetime)
    Service->>Service: validateServiceAccount(non-blank)
    Service->>Service: validateScopes(anyMatch SUPPORTED_SCOPES)
    Service->>Service: parseLifetimeSeconds(cap at MAX 3600s)
    Service-->>Controller: GeneratedAccessToken(prefix+UUID, expireTime)
    Controller-->>Client: "200 { accessToken, expireTime }"

    Note over Client, Service: Error cases
    Client->>Controller: POST (missing/unsupported scope or malformed lifetime)
    Controller->>Service: generateAccessToken(...)
    Service-->>Controller: throws GcpException(INVALID_ARGUMENT)
    Controller-->>Client: "400 { error: { status: INVALID_ARGUMENT } }"
Loading

Reviews (4): Last reviewed commit: "feat(iamcredentials): add generateAccess..." | Re-trigger Greptile

Comment thread src/main/java/io/floci/gcp/services/iamcredentials/IamCredentialsController.java Outdated
Adds the IAM Credentials REST emulator surface for local credential vending, including generateAccessToken validation, service enablement wiring, REST tests, and Java generated-client compatibility coverage.

- [x] New feature (`feat:`)

Implements the IAM Credentials v1 HTTP/JSON generateAccessToken path used by the Google Java IAM Credentials client. Verified with IamCredentialsServiceTest, IamCredentialsRestIntegrationTest, IamCredentialsDisabledRestIntegrationTest, IamServiceTest, and compatibility-tests/sdk-test-java IamCredentialsTest against a running emulator.

- [x] `./mvnw test` passes locally
- [x] New or updated integration test added
- [x] Commit messages follow Conventional Commits
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant